package givenchy
 
// 缓存接口，提供ip缓存和任务缓存
//ip缓存为数据库和客户端之间的缓存，当客户端提交一个ip时，先在缓存中找，没有再到db中找，没有才新建。
//如果已经存在就累加记数，并算出小时数。因为这个方法只检查和保存最后一次的ip状态，所以同一个ip不要重复检查
//
//任务缓存接口对客户端来说是一个只读接口，客户端只根据规则读取和处理任务
//另外有一个线程去维护任务缓存的增加和删除
// 使用用户id作为key，taskGroup作为值

class CacheService {

    //boolean transactional = true
    
    private static final Map<String, Iplog>  IP_CACHE = Collections.synchronizedMap(new HashMap<String, Iplog>());  


    private static final Map<Long, TaskGroup>  TASK_CACHE = Collections.synchronizedMap(new HashMap<Long, TaskGroup>());  
    private static final Map<Long, Set>  USER_LOG_CACHE = Collections.synchronizedMap(new HashMap<Long, Set>());  

    public static int RETURN_TOTAL = 10 // 每次返回客户端的task个数
    
    // =========================================================
    // ===== ip 相关的 =======================================
    // =========================================================
    def checkIP(String key) {
        // 1,检查cache，和DB，没有就新建一个
        def iplog = this.cache(key){
            new Iplog(ip : key )
        }
        // 不是第一次就更新last
        if(iplog.ipcount > 0){ 
            iplog.last = (new Date() - iplog.lastTime) * 24 + new Date().hours - iplog.lastTime.hours
            if(iplog.last < 0) iplog.last = 0
            iplog.lastTime = new Date() 
        }

        iplog.ipcount++
        return iplog
    }

  
// 同步ip日志，，到数据库
    def sync = {
        IP_CACHE.each{ key, value ->
            value.sync()
        }
    }
 
    /**
     * 缓存一个对象，
     */
    def cache(Serializable key,  Closure callable) {
        // 现在缓存里找，没有再到DB里找，最后执行callback函数新创建一个。
        def entry = IP_CACHE.get(key)
        
        if (!entry) { 
                if (!entry) entry = Iplog.findByIp(key)
                if (!entry){
                    entry = callable.call() 
                    entry.save(flush:true)
                    }
                IP_CACHE.put(key, entry)
        }

        return entry
    }

    // =========================================================
    // ===== Task 相关的 =======================================
    // =========================================================
    // 所有积分大于100的用户才放在缓存里，
    // 根据和ip和RETURN_TOTAL的质量去查询task，
    def giveTask(int ipbest ,  Long userid){
        def userLog = cacheUserLog(userid)
        def result = []
 
        def return_count = 0
        TASK_CACHE.each{key, value ->
            if (!userLog.contains(value.id)) { 
                if (return_count < RETURN_TOTAL) {
                    
                    def script = value.checkTask(ipbest )
                    if (script) {
                        result.add(script)
                        log.info "cache task pass :${script}"
                        if (!value.person.isAttached()) {
                            value.person.attach()
                        }
                         
                        value.person.total--
                        value.person.merge()
                        return_count++
                        userLog.add(value.id)
                        new Logs(
                        	    sourceId : userid,
                                siteId :  value.person?.id,
                                username :  value.person?.username,
                                taskId : value.id,
                                taskname : value.name
                        ).save()
                    } 
                    //value.save()
                }
            }
        }
        //println result
    
        return result 
    }

 /**
     * 缓存一个对象，
     */
    def addTask(Serializable key,  TaskGroup value) {
        // 现在缓存里找，没有再到DB里找，最后执行callback函数新创建一个。
        def entry = TASK_CACHE.get(key)
        
        if (!entry) {  
                TASK_CACHE.put(key, value)
        } 
    }
    /**
     * 删除一个对象，
     */
    def removeTask(Serializable key) { 
       TASK_CACHE.remove(key)  
    }

    // initTask只是添加列表，
    def initTask = {
            User.findAllByVipGreaterThanOrTotalGreaterThan(0,100).each{
            def tasks = TaskGroup.findAllByPerson(it)
            tasks.each{task ->
                addTask( task.id , task)
            } 
        }
    }
    // syncTask包括添加和删除
    synchronized  def syncTask = {
         initTask()
         def removes = []
          TASK_CACHE.each{key, value ->
             
            def u = User.get(value.person.id)
            if (u) {
                if (u.vip <=0) {
                    if (u.total <=10) {
                        removes.add(key)
                    }
                }
            }else{
                removes.add(key)
            }
          }

          removes.each{
            removeTask(it)
          }
    }

    // =========================================================
    // ===== 用户日志 相关的 =======================================
    // =========================================================
   /**
     * 缓存一个对象，
     */
    def cacheUserLog(Serializable key) {
        // 现在缓存里找，没有再到DB里找，最后执行callback函数新创建一个。
        def entry = USER_LOG_CACHE.get(key)
        
        if (!entry) {  
                entry = new UserLogSet()
                USER_LOG_CACHE.put(key, entry)
        }
        return entry
    }

    def syncUserLog = {
        USER_LOG_CACHE.each{key, value ->
            value.sync()
        }
    }

    def syncPerUser(Serializable key){
        def entry = cacheUserLog(key)
        entry.clear()
    }
    // =========================================================
    // ===== Test 相关的 =======================================
    // =========================================================


    def testTask = {
        log.info "task_cache size : ${TASK_CACHE.size()}"
        TASK_CACHE.each{key, value ->
            log.info     "===task" +  value
        }
    }   

    def testIP = {
        log.info "ip_cache size : ${IP_CACHE.size()}"
        IP_CACHE.each{key, value ->
            log.info    "===iplog" +    value
        }
    }   

    def testUserLog = {
        log.info "user_log_cache size : ${USER_LOG_CACHE.size()}"
        USER_LOG_CACHE.each{key, value ->
            log.info    "===user_log" +    value
        }
    } 
}
